import math
from typing import Callable

from gui.signals import SIGNALS
from utils.reference import ValueRange, ConstItem, fast_json


class EnumAttribute:
    YIN = ConstItem('yin', '阴')
    YANG = ConstItem('yang', '阳')
    WOOD = ConstItem('wood', '木')
    FIRE = ConstItem('fire', '火')
    EARTH = ConstItem('earth', '土')
    METAL = ConstItem('metal', '金')
    WATER = ConstItem('water', '水')


class PlayerAttributeItem:
    __slots__ = ('attr_type', 'value')

    def __init__(self, attr_type, value=0):
        self.attr_type = attr_type
        self.value = value


class PlayerAttribute:
    __slots__ = ('yang', 'yin', 'wood', 'fire', 'earth', 'metal', 'water')

    def __init__(self, data=None):
        self.yin = PlayerAttributeItem(EnumAttribute.YIN)
        self.yang = PlayerAttributeItem(EnumAttribute.YANG)
        self.metal = PlayerAttributeItem(EnumAttribute.METAL)
        self.wood = PlayerAttributeItem(EnumAttribute.WOOD)
        self.water = PlayerAttributeItem(EnumAttribute.WATER)
        self.fire = PlayerAttributeItem(EnumAttribute.FIRE)
        self.earth = PlayerAttributeItem(EnumAttribute.EARTH)

        if data is not None:
            self.set_data(data)

    def __json__(self):
        return {
            'yin': self.yin.value,
            'yang': self.yang.value,
            'metal': self.metal.value,
            'wood': self.wood.value,
            'fire': self.fire.value,
            'earth': self.earth.value,
            'water': self.water.value,
        }

    def set_data(self, data):
        for key, value in data.items():
            pai: PlayerAttributeItem = getattr(self, key)
            pai.value = value

    @property
    def values(self):
        attrs = (getattr(self, key) for key in self.__slots__)
        return ' '.join(f'{attr.attr_type}({attr.value})' for attr in attrs)


class PlayerState:
    def __init__(self):
        self.level = 0
        self.exp = ValueRange(100, current=0)
        self.hp = ValueRange(100)
        self.mp = ValueRange(100)
        self.attack = 10
        self.defense = 5
        self.qi_rate = 10  # 集气速率
        self.qi = ValueRange(100, 0)
        self.dodge = 0

        self.strength = 5
        self.attribute = PlayerAttribute()

        self.take_damage = 100  # 承伤系数 100%

    def __json__(self):
        return fast_json(self)

    def load(self, data: dict):
        self.level = data['level']
        self.exp.load(data['exp'])
        self.hp.load(data['hp'])
        self.mp.load(data['mp'])
        self.attribute.set_data(data['attribute'])
        self.attack = data['attack']
        self.defense = data['defense']
        self.qi_rate = data['qi_rate']
        self.qi.load(data['qi'])
        self.dodge = data['dodge']
        self.strength = data['strength']
        self.take_damage = data['take_damage']

    def level_up(self):
        self.level += 1
        self.exp = ValueRange(100 + (self.level - 1) * 50, current=0)
        self.hp = ValueRange(math.floor(100 + 10 * math.pow(self.level, 1.2)))
        self.mp = ValueRange(math.floor(100 + 2 * math.pow(self.level, 1.1)))
        self.attack = math.floor(10 + 5 * math.log(1 + self.level))
        self.defense = math.floor(5 + 2 * math.pow(self.level, 0.7))
        SIGNALS.send_message.emit(f'<span style="color:red">升级了!</span>')

    def add_exp(self, num):
        new_exp = self.exp.current + num
        if new_exp >= self.exp.maximum:
            delta = new_exp - self.exp.maximum
            self.level_up()
            self.exp.current = delta
        else:
            self.exp.current = new_exp


def calculate_damage(attacker_level, attacker_attack, skill_multiplier, skill_penetration,
                     defender_level, defender_base_def, defender_equipment_def,
                     defender_equipment_durability_current, defender_equipment_durability_max,
                     defender_equipment_def_values, K=200, debug=False):
    """
    计算RPG游戏中的伤害值

    参数:
    - attacker_level: 攻击方等级
    - attacker_attack: 攻击方攻击力
    - skill_multiplier: 技能倍率
    - skill_penetration: 技能穿透比例(0-1)
    - defender_level: 防御方等级
    - defender_base_def: 防御方基础防御力
    - defender_equipment_def: 防御方装备总防御力
    - defender_equipment_durability_current: 装备当前总耐久度列表
    - defender_equipment_durability_max: 装备最大总耐久度列表
    - defender_equipment_def_values: 各装备防御力值列表
    - K: 防御常数(默认200)
    - debug: 是否输出调试信息

    返回:
    - damage: 造成的伤害
    - durability_consumption: 各装备耐久消耗列表
    - effective_defense: 实际生效防御力
    """

    # 1. 计算等级差
    DL = attacker_level - defender_level

    # 2. 计算总防御力
    total_defense = defender_base_def + defender_equipment_def

    # 3. 计算耐久系数
    durability_factor = sum(defender_equipment_durability_current) / sum(defender_equipment_durability_max)

    # 4. 计算有效防御力(考虑耐久)
    effective_defense_with_durability = defender_base_def + defender_equipment_def * durability_factor

    # 5. 计算等级压制穿甲
    if DL > 0:
        # 等级压制穿甲系数
        level_penetration = min(0.05 + DL * 0.02, 0.5)
    else:
        level_penetration = 0

    # 6. 计算总穿透比例(乘法叠加)
    total_penetration = 1 - (1 - level_penetration) * (1 - skill_penetration)

    # 7. 计算实际生效防御力(考虑穿透)
    effective_defense = effective_defense_with_durability * (1 - total_penetration)

    # 8. 计算伤害减免比例
    damage_reduction = effective_defense / (effective_defense + K)

    # 9. 计算基础伤害
    base_damage = attacker_attack * skill_multiplier

    # 10. 计算最终伤害
    final_damage = base_damage * (1 - damage_reduction)

    # 11. 计算耐久消耗(仅当DL>0时)
    durability_consumption = [0] * len(defender_equipment_def_values)
    if DL > 0:
        # 计算被装备抵消的伤害
        equipment_mitigated_damage = base_damage * damage_reduction * (defender_equipment_def / total_defense)

        # 基础耐久消耗
        base_durability_cost = 2  # 可调整

        # 等级压制加成
        level_penalty = 1 + DL * 0.05

        # 总耐久消耗
        total_durability_cost = base_durability_cost * level_penalty

        # 按装备防御力比例分摊耐久消耗
        total_equipment_def = sum(defender_equipment_def_values)
        if total_equipment_def > 0:
            for i, eq_def in enumerate(defender_equipment_def_values):
                durability_consumption[i] = total_durability_cost * (eq_def / total_equipment_def)

    # 调试信息
    if debug:
        print(f"=== 战斗计算详情 ===")
        print(f"等级差(DL): {DL}")
        print(f"总防御力: {total_defense}")
        print(f"耐久系数: {durability_factor:.2f}")
        print(f"考虑耐久的有效防御力: {effective_defense_with_durability:.1f}")
        print(f"等级穿透比例: {level_penetration:.2f}")
        print(f"总穿透比例: {total_penetration:.2f}")
        print(f"实际生效防御力: {effective_defense:.1f}")
        print(f"伤害减免比例: {damage_reduction:.2f}")
        print(f"基础伤害: {base_damage:.1f}")
        print(f"最终伤害: {final_damage:.1f}")
        if DL > 0:
            print(f"耐久消耗: {[f'{x:.1f}' for x in durability_consumption]}")
        print("===================")

    return max(0, final_damage), durability_consumption, effective_defense


# 辅助函数：更新装备耐久度
def update_equipment_durability(current_durability, durability_consumption):
    """
    更新装备耐久度

    参数:
    - current_durability: 当前耐久度列表
    - durability_consumption: 耐久消耗列表

    返回:
    - new_durability: 更新后的耐久度列表
    """
    new_durability = []
    for i in range(len(current_durability)):
        new_durability.append(max(0, current_durability[i] - durability_consumption[i]))
    return new_durability
